package com.dd.stack.se.stream.simple.practice;

import com.dd.stack.se.stream.simple.datasource.CustomData;
import com.dd.stack.se.stream.simple.pijo.StudentBO;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @Author liuxianmeng
 * @CreateTime 2024/11/14 23:33
 * @Description Stream流的基础使用方法
 */
public class BasicUsageImpl implements BasicUsage {

    /**
     * 使用JUnit5的断言来验证每个学生都满足 年龄大于18岁且参加了高级课程的条件
     */
    @Override
    public List<StudentBO> filterToList() {
        // 假设 CustomData.studentBOS 已经被正确初始化
        return CustomData.studentBOS.stream()
                .filter(student -> student.getAge() > 18 && student.isEnrolledInAdvancedCourses())
                .collect(Collectors.toList());
    }

    @Override
    public List<StudentBO> sortMap() {
        return CustomData.studentBOS.stream()
                // 按照成绩降序排序
                .sorted((s1, s2) -> Double.compare(s1.getScore(), s2.getScore()))
                .map(student -> {
                    // 对每个学生的课程成绩进行处理，只保留成绩大于等于 80 的课程
                    Map<String, Integer> filteredGrades = student.getCourseGrades().entrySet().stream()
                            .filter(entry -> entry.getValue() >= 80)
                            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
                    student.setCourseGrades(filteredGrades);
                    return student;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<StudentBO> limit() {
        return CustomData.studentBOS.stream()
                // 首先过滤出爱好数量不少于0个的学生
                .filter(student -> student.getHobbies().size() >= 0)
                // 按照平均绩点进行降序排序【默认升序 reverse降序】
                .sorted(((o1, o2) -> o2.getGpa().compareTo(o1.getGpa())))
                // 取前5个学生
                .limit(5)
                .collect(Collectors.toList());
    }

    private List<StudentBO> limit2() {
        return CustomData.studentBOS.stream()
                // 先进行null检查，过滤掉studentBOS为null的情况
                .filter(student -> student!= null && student.getHobbies()!= null)
                // 过滤出爱好数量不少于3个的学生
                .filter(student -> student.getHobbies().size() >= 3)
                // 按照平均绩点进行降序排序，同时处理getGpa返回null的情况，这里假设null值的学生排在最后
                .sorted(Comparator.comparing(student -> student.getGpa() == null? Double.MIN_VALUE : student.getGpa(), Comparator.reverseOrder()))
                // 取前5个学生
                .limit(5)
                .collect(Collectors.toList());
    }

    private List<StudentBO> limit3() {
        return CustomData.studentBOS.stream()
                // 使用Optional包装每个学生对象，以便更优雅地处理null情况
                .map(Optional::ofNullable)
                // 过滤掉为Optional.empty()的情况（即原始student为null的情况）
                .filter(Optional::isPresent)
                // 提取出Optional中的学生对象进行后续操作
                .map(Optional::get)
                // 过滤出爱好数量不少于3个的学生，通过Optional处理hobbies可能为null的情况
                .filter(student -> Optional.ofNullable(student.getHobbies()).map(List::size).orElse(0) >= 3)
                // 按照平均绩点进行降序排序，通过Optional处理gpa可能为null的情况
                .sorted(Comparator.comparing(student -> Optional.ofNullable(student.getGpa()).orElse(Double.MIN_VALUE), Comparator.reverseOrder()))
                // 取前5个学生
                .limit(5)
                // 将处理后的学生对象收集为列表
                .collect(Collectors.toList());
    }

    @Override
    public Map<String, Long> groupingByCounting() {
        return CustomData.studentBOS.stream()
                // 过滤出参加高级课程且平均绩点大于3.0的学生
                .filter(student -> student.isEnrolledInAdvancedCourses() && student.getGpa() > 3.0)
                // 提取学生所在城市作为分组依据
                .map(StudentBO::getAddress)
                .map(Address -> Address.getCity())
                // 按照城市进行分组，并统计每组的学生数量
                .collect(Collectors.groupingBy(city -> city, Collectors.counting()));
    }

    public Map<String, Long> groupingBy2() {
        return CustomData.studentBOS.stream()
                // 先进行null检查，过滤掉studentBOS为null的情况
                .filter(student -> student!= null)
                // 过滤出参加高级课程且平均绩点大于3.0的学生，同时处理getGpa返回null的情况
                .filter(student -> student.isEnrolledInAdvancedCourses() && (student.getGpa() == null || student.getGpa() > 3.0))
                // 提取学生所在城市作为分组依据，先处理getAddress返回null的情况
                .map(student -> student.getAddress() == null? null : student.getAddress())
                .filter(address -> address!= null)
                .map(Address -> Address.getCity())
                // 按照城市进行分组，并统计每组的学生数量
                .collect(Collectors.groupingBy(city -> city == null? "" : city, Collectors.counting()));
    }

    public Map<String, Long> groupingBy3() {
        return CustomData.studentBOS.stream()
                // 使用Optional包装每个学生对象
                .map(Optional::ofNullable)
                // 过滤掉为Optional.empty()的情况
                .filter(Optional::isPresent)
                // 提取出Optional中的学生对象
                .map(Optional::get)
                // 过滤出参加高级课程且平均绩点大于3.0的学生，通过Optional处理gpa可能为null的情况
                .filter(student -> student.isEnrolledInAdvancedCourses() && Optional.ofNullable(student.getGpa()).orElse(0.0) > 3.0)
                // 提取学生所在城市作为分组依据，通过Optional处理address可能为null的情况
                .map(student -> Optional.ofNullable(student.getAddress()).map(Address -> Address.getCity()).orElse(null))
                // 按照城市进行分组，并统计每组的学生数量，处理城市名为null的情况，将其归为一个特定的默认分组（这里为空字符串分组）
                .collect(Collectors.groupingBy(city -> city == null? "" : city, Collectors.counting()));
    }

    @Override
    public Map<String, Integer> containsToMap() {
        return CustomData.studentBOS.stream()
                // 过滤出有“数学”课程成绩的学生
                .filter(student -> student.getCourseGrades().containsKey("数学"))
                .collect(Collectors.toMap(StudentBO::getName, student -> student.getCourseGrades().get("数学")));
    }

    public Map<String, Integer> findTop3StudentsMathScores2() {
        return CustomData.studentBOS.stream()
                // 先进行null检查，过滤掉studentBOS为null的情况
                .filter(student -> student!= null)
                // 过滤出有“数学”课程成绩的学生，同时处理getCourseGrades返回null的情况
                .filter(student -> student.getCourseGrades()!= null && student.getCourseGrades().containsKey("数学"))
                // 按照“数学”成绩降序排序，处理成绩为null的情况，这里假设null成绩排在最后
                .sorted(Comparator.comparing(student -> student.getCourseGrades().get("数学") == null? Integer.MIN_VALUE : student.getCourseGrades().get("数学"), Comparator.reverseOrder()))
                // 取前3名学生
                .limit(3)
                .collect(Collectors.toMap(
                        student -> student.getName() == null? "" : student.getName(),
                        student -> student.getCourseGrades().get("数学") == null? 0 : student.getCourseGrades().get("数学")
                ));
    }

    public Map<String, Integer> findTop3StudentsMathScores3() {
        return CustomData.studentBOS.stream()
                // 使用Optional包装每个学生对象
                .map(Optional::ofNullable)
                // 过滤掉为Optional.empty()的情况
                .filter(Optional::isPresent)
                // 提取出Optional中的学生对象
                .map(Optional::get)
                // 过滤出有“数学”课程成绩的学生，通过Optional处理courseGrades可能为null的情况
                .filter(student -> Optional.ofNullable(student.getCourseGrades()).map(grades -> grades.containsKey("数学")).orElse(false))
                // 按照“数学”成绩降序排序，通过Optional处理成绩为null的情况
                .sorted(Comparator.comparing(student -> Optional.ofNullable(student.getCourseGrades()).map(grades -> grades.get("数学")).orElse(Integer.MIN_VALUE), Comparator.reverseOrder()))
                // 取前3名学生
                .limit(3)
                // 构建映射表，通过Optional处理name和成绩可能为null的情况
                .collect(Collectors.toMap(
                        student -> Optional.ofNullable(student.getName()).orElse(""),
                        student -> Optional.ofNullable(student.getCourseGrades()).map(grades -> grades.get("数学")).orElse(0)
                ));
    }
}
